from celery import shared_task
from django.utils import timezone
from .models import DataSyncTask, DataSyncLog
import logging
import json
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

logger = logging.getLogger(__name__)

def send_websocket_notification(task_type, progress_data):
    """
    发送WebSocket通知
    """
    try:
        channel_layer = get_channel_layer()
        if channel_layer:
            async_to_sync(channel_layer.group_send)(
                f'download_progress_{task_type}',
                {
                    'type': 'download_progress_update',
                    'progress_data': progress_data
                }
            )
    except Exception as e:
        logger.error(f"发送WebSocket通知失败: {str(e)}")

@shared_task
def sync_fund_data_task(task_id, fund_codes=None, sync_net_value=True):
    """
    异步同步基金数据任务
    task_id: 同步任务ID
    fund_codes: 基金代码列表
    sync_net_value: 是否同步净值数据
    """
    try:
        # 更新任务状态为运行中
        task = DataSyncTask.objects.get(id=task_id)
        task.status = 'running'
        task.last_sync_time = timezone.now()
        task.save()
        
        # 发送WebSocket通知 - 任务开始
        send_websocket_notification(task.task_type, {
            'status': 'running',
            'progress': 0,
            'message': '开始同步基金数据',
            'start_time': timezone.now().isoformat()
        })
        
        # 创建同步日志
        log = DataSyncLog.objects.create(
            task=task,
            start_time=timezone.now(),
            status='running'
        )
        
        try:
            # 动态导入AKShare服务（避免启动时导入错误）
            from .akshare_service import akshare_service
            
            # 执行数据同步
            result = akshare_service.sync_fund_data(
                fund_codes=fund_codes,
                sync_net_value=sync_net_value
            )
            
            # 更新任务状态为成功
            task.status = 'completed'
            task.save()
            
            # 发送WebSocket通知 - 任务完成
            send_websocket_notification(task.task_type, {
                'status': 'completed',
                'progress': 100,
                'message': f"同步完成: 成功 {result['success']}, 失败 {result['error']}",
                'end_time': timezone.now().isoformat(),
                'success_count': result['success'],
                'error_count': result['error']
            })
            
            # 更新日志
            log.status = 'success'
            log.end_time = timezone.now()
            log.success_records = result['success']
            log.failed_records = result['error']
            log.total_records = result['success'] + result['error']
            log.save()
            
            logger.info(f"任务 {task_id} 同步完成: {result}")
            return result
            
        except ImportError as e:
            error_msg = f"导入AKShare服务失败: {str(e)}"
            logger.error(error_msg)
            
            # 更新任务状态为失败
            task.status = 'failed'
            task.save()
            
            # 发送WebSocket通知 - 任务失败
            send_websocket_notification(task.task_type, {
                'status': 'failed',
                'progress': 0,
                'message': error_msg,
                'error': str(e),
                'end_time': timezone.now().isoformat()
            })
            
            # 更新日志
            log.status = 'failed'
            log.error_message = error_msg
            log.end_time = timezone.now()
            log.save()
            
            return {'success': 0, 'error': 1, 'message': error_msg}
            
        except Exception as e:
            error_msg = f"同步基金数据失败: {str(e)}"
            logger.error(error_msg)
            
            # 更新任务状态为失败
            task.status = 'failed'
            task.save()
            
            # 更新日志
            log.status = 'failed'
            log.error_message = error_msg
            log.end_time = timezone.now()
            log.save()
            
            return {'success': 0, 'error': 1, 'message': error_msg}
            
    except DataSyncTask.DoesNotExist:
        error_msg = f"同步任务 {task_id} 不存在"
        logger.error(error_msg)
        return {'success': 0, 'error': 1, 'message': error_msg}
    
    except Exception as e:
        error_msg = f"任务执行失败: {str(e)}"
        logger.error(error_msg)
        return {'success': 0, 'error': 1, 'message': error_msg}

@shared_task
def sync_fund_net_value_task(task_id, fund_code, days=30):
    """
    异步同步单个基金净值数据任务
    task_id: 同步任务ID
    fund_code: 基金代码
    days: 同步天数
    """
    task = None
    log = None
    try:
        # 更新任务状态
        task = DataSyncTask.objects.get(id=task_id)
        task.status = 'running'
        task.last_sync_time = timezone.now()
        task.save()
        
        # 创建同步日志
        log = DataSyncLog.objects.create(
            task=task,
            start_time=timezone.now(),
            status='running'
        )
        
        try:
            # 动态导入AKShare服务
            from .akshare_service import akshare_service
            from .models import FundInfo, FundNavDetail
            from datetime import datetime, timedelta
            
            # 获取基金对象
            fund_data = FundInfo.objects.get(fund_code=fund_code)
            
            # 计算日期范围
            end_date = datetime.now()
            start_date = end_date - timedelta(days=days)
            
            # 获取净值数据
            net_values = akshare_service.fetch_fund_net_value(
                fund_code=fund_code,
                start_date=start_date.strftime('%Y%m%d'),
                end_date=end_date.strftime('%Y%m%d')
            )
            
            # 保存净值数据
            success_count = 0
            for net_value_data in net_values:
                try:
                    FundNavDetail.objects.update_or_create(
                        fund_code=fund_data.fund_code,
                        nav_date=net_value_data['nav_date'],
                        defaults={
                            'unit_nav': net_value_data['unit_nav'],
                            'cumulative_nav': net_value_data['accumulated_nav'],
                            'daily_growth_rate': net_value_data.get('daily_return'),
                        }
                    )
                    success_count += 1
                except Exception as e:
                    logger.error(f"保存净值数据失败: {e}")
                    continue
            
            # 更新任务状态
            task.status = 'completed'
            task.save()
            
            # 更新日志
            log.status = 'success'
            log.success_records = success_count
            log.failed_records = 0
            log.total_records = success_count
            log.end_time = timezone.now()
            log.save()
            
            logger.info(f"基金 {fund_code} 净值同步完成: {success_count} 条")
            return {'success': success_count, 'error': 0}
            
        except ImportError as e:
            error_msg = f"导入AKShare服务失败: {str(e)}"
            logger.error(error_msg)
            
            task.status = 'failed'
            task.save()
            
            log.status = 'failed'
            log.error_message = error_msg
            log.end_time = timezone.now()
            log.save()
            
            return {'success': 0, 'error': 1, 'message': error_msg}
            
        except Exception as e:
            error_msg = f"同步净值数据失败: {str(e)}"
            logger.error(error_msg)
            
            try:
                if task is not None:
                    task.status = 'failed'
                    task.save()
                
                if log is not None:
                    log.status = 'failed'
                    log.error_message = str(e)
                    log.end_time = timezone.now()
                    log.save()
            except Exception:
                pass
            
            return {'success': 0, 'error': 1, 'message': error_msg}
            
    except DataSyncTask.DoesNotExist:
        error_msg = f"同步任务 {task_id} 不存在"
        logger.error(error_msg)
        return {'success': 0, 'error': 1, 'message': error_msg}
    
    except Exception as e:
        error_msg = f"任务执行失败: {str(e)}"
        logger.error(error_msg)
        return {'success': 0, 'error': 1, 'message': error_msg}

@shared_task
def download_fund_list_task(task_id):
    """
    下载基金清单任务
    """
    task = None
    log = None
    try:
        from .akshare_service import akshare_service
        from .models import FundInfo
        from django.db import transaction
        
        # 获取任务
        task = DataSyncTask.objects.get(id=task_id)
        task.status = 'running'
        task.started_at = timezone.now()
        task.save()
        
        # 创建日志
        log = DataSyncLog.objects.create(
            task=task,
            start_time=timezone.now(),
            status='running'
        )
        
        # 发送WebSocket通知
        send_websocket_notification('fund_list', {
            'status': 'running',
            'message': '开始下载基金清单',
            'progress': 0
        })
        
        # 获取基金清单数据
        fund_list = akshare_service.fetch_fund_list()
        
        if not fund_list:
            raise Exception("未获取到基金清单数据")
        
        total_count = len(fund_list)
        success_count = 0
        error_count = 0
        
        # 清空现有数据（覆盖更新）
        with transaction.atomic():
            FundInfo.objects.all().delete()
            
            for i, fund_data in enumerate(fund_list):
                try:
                    FundInfo.objects.create(
                        fund_code=fund_data['fund_code'],
                        fund_name=fund_data['fund_name'],
                        fund_type=fund_data['fund_type'],
                        data_source='akshare'
                    )
                    success_count += 1
                    
                    # 发送进度更新
                    progress = int((i + 1) / total_count * 100)
                    send_websocket_notification('fund_list', {
                        'status': 'running',
                        'message': f'正在下载基金清单 {i+1}/{total_count}',
                        'progress': progress,
                        'total': total_count,
                        'completed': i + 1
                    })
                    
                except Exception as e:
                    logger.error(f"保存基金数据失败: {e}")
                    error_count += 1
                    continue
        
        # 更新任务状态
        task.status = 'completed'
        task.completed_at = timezone.now()
        task.save()
        
        # 更新日志
        log.status = 'success'
        log.end_time = timezone.now()
        log.success_records = success_count
        log.failed_records = error_count
        log.total_records = total_count
        log.save()
        
        # 发送完成通知
        send_websocket_notification('fund_list', {
            'status': 'completed',
            'message': f'基金清单下载完成: 成功 {success_count} 个',
            'progress': 100,
            'total': total_count,
            'completed': success_count
        })
        
        logger.info(f"基金清单下载完成: 成功 {success_count} 个，失败 {error_count} 个")
        return {'success': success_count, 'error': error_count}
        
    except Exception as e:
        error_msg = f"下载基金清单失败: {str(e)}"
        logger.error(error_msg)
        
        try:
            if task is not None:
                task.status = 'failed'
                task.completed_at = timezone.now()
                task.save()
            
            if log is not None:
                log.status = 'failed'
                log.error_message = str(e)
                log.end_time = timezone.now()
                log.save()
        except Exception:
            pass
        
        # 发送错误通知
        send_websocket_notification('fund_list', {
            'status': 'failed',
            'message': error_msg,
            'progress': 0
        })
        
        return {'success': 0, 'error': 1, 'message': error_msg}

@shared_task
def download_fund_details_task(task_id, fund_codes=None):
    """
    下载基金详细信息任务
    """
    task = None
    log = None
    try:
        from .akshare_service import akshare_service
        from .models import FundInfo, FundInfoDetail
        from django.db import transaction
        
        # 获取任务
        task = DataSyncTask.objects.get(id=task_id)
        task.status = 'running'
        task.started_at = timezone.now()
        task.save()
        
        # 创建日志
        log = DataSyncLog.objects.create(
            task=task,
            start_time=timezone.now(),
            status='running'
        )
        
        # 发送WebSocket通知
        send_websocket_notification('fund_details', {
            'status': 'running',
            'message': '开始下载基金详细信息',
            'progress': 0
        })
        
        # 获取需要下载的基金列表
        if fund_codes:
            funds = FundInfo.objects.filter(fund_code__in=fund_codes)
        else:
            funds = FundInfo.objects.all()
        
        total_count = funds.count()
        success_count = 0
        error_count = 0
        
        # 清空现有详细信息数据（覆盖更新）
        with transaction.atomic():
            FundInfoDetail.objects.all().delete()
            
            for i, fund in enumerate(funds):
                try:
                    # 检查任务是否被取消
                    task.refresh_from_db()
                    if task.status == 'cancelled':
                        logger.info(f"任务 {task_id} 已被取消，停止下载")
                        # 发送取消通知
                        send_websocket_notification('fund_details', {
                            'status': 'cancelled',
                            'message': '任务已被用户取消',
                            'progress': int((i + 1) / total_count * 100)
                        })
                        return {'success': success_count, 'error': error_count, 'cancelled': True}
                    
                    # 获取基金详细信息
                    detail_info = akshare_service.fetch_fund_basic_info_xq(fund.fund_code)
                    
                    if detail_info:
                        FundInfoDetail.objects.create(
                            fund_code=detail_info['fund_code'],
                            fund_name=detail_info['fund_name'],
                            fund_full_name=detail_info['fund_full_name'],
                            establishment_date=detail_info['establishment_date'],
                            latest_scale=detail_info['fund_size'],
                            fund_company=detail_info['fund_company'],
                            fund_manager=detail_info['fund_manager'],
                            custodian_bank=detail_info['custodian_bank'],
                            fund_type=detail_info['fund_type'],
                            rating_agency=detail_info['rating_agency'],
                            fund_rating=detail_info['fund_rating'],
                            investment_strategy=detail_info['investment_strategy'],
                            investment_objective=detail_info['investment_objective'],
                            performance_benchmark=detail_info['benchmark'],
                            data_source='akshare'
                        )
                        success_count += 1
                    else:
                        error_count += 1
                    
                    # 发送进度更新
                    progress = int((i + 1) / total_count * 100)
                    send_websocket_notification('fund_details', {
                        'status': 'running',
                        'message': f'正在下载基金详细信息 {i+1}/{total_count}',
                        'progress': progress,
                        'total': total_count,
                        'completed': i + 1
                    })
                    
                except Exception as e:
                    logger.error(f"下载基金 {fund.fund_code} 详细信息失败: {e}")
                    error_count += 1
                    continue
        
        # 检查任务是否被取消
        task.refresh_from_db()
        if task.status != 'cancelled':
            # 更新任务状态
            task.status = 'completed'
            task.completed_at = timezone.now()
            task.save()
            
            # 更新日志
            log.status = 'success'
            log.success_records = success_count
            log.failed_records = error_count
            log.total_records = total_count
            log.end_time = timezone.now()
            log.save()
            
            # 发送完成通知
            send_websocket_notification('fund_details', {
                'status': 'completed',
                'message': f'基金详细信息下载完成: 成功 {success_count} 个',
                'progress': 100,
                'total': total_count,
                'completed': success_count
            })
        else:
            # 任务已被取消，更新日志
            log.status = 'cancelled'
            log.success_records = success_count
            log.failed_records = error_count
            log.total_records = total_count
            log.end_time = timezone.now()
            log.error_message = '任务已被用户取消'
            log.save()
        
        logger.info(f"基金详细信息下载完成: 成功 {success_count} 个，失败 {error_count} 个")
        return {'success': success_count, 'error': error_count}
        
    except Exception as e:
        error_msg = f"下载基金详细信息失败: {str(e)}"
        logger.error(error_msg)
        
        try:
            if task is not None:
                task.status = 'failed'
                task.completed_at = timezone.now()
                task.save()
            
            if log is not None:
                log.status = 'failed'
                log.error_message = str(e)
                log.end_time = timezone.now()
                log.save()
        except Exception:
            pass
        
        # 发送错误通知
        send_websocket_notification('fund_details', {
            'status': 'failed',
            'message': error_msg,
            'progress': 0
        })
        
        return {'success': 0, 'error': 1, 'message': error_msg}

@shared_task
def download_fund_nav_task(task_id, fund_codes=None):
    """
    下载基金净值任务
    """
    task = None
    log = None
    try:
        from .akshare_service import akshare_service
        from .models import FundInfo, FundNavDetail
        from django.db import transaction
        
        # 获取任务
        task = DataSyncTask.objects.get(id=task_id)
        task.status = 'running'
        task.started_at = timezone.now()
        task.save()
        
        # 创建日志
        log = DataSyncLog.objects.create(
            task=task,
            start_time=timezone.now(),
            status='running'
        )
        
        # 发送WebSocket通知
        send_websocket_notification('fund_nav', {
            'status': 'running',
            'message': '开始下载基金净值',
            'progress': 0
        })
        
        # 获取需要下载的基金列表
        if fund_codes:
            funds = FundInfo.objects.filter(fund_code__in=fund_codes)
        else:
            funds = FundInfo.objects.all()
        
        total_count = funds.count()
        success_count = 0
        error_count = 0
        
        # 清空现有净值数据（覆盖更新）
        with transaction.atomic():
            FundNavDetail.objects.all().delete()
            
            for i, fund in enumerate(funds):
                try:
                    # 获取基金净值数据
                    nav_data = akshare_service.fetch_fund_open_fund_info_em(
                        symbol=fund.fund_code, 
                        indicator="单位净值走势"
                    )
                    
                    if nav_data:
                        for nav_item in nav_data:
                            FundNavDetail.objects.create(
                                fund_code=nav_item['fund_code'],
                                fund_name=nav_item['fund_name'],
                                nav_date=nav_item['nav_date'],
                                unit_nav=nav_item['unit_nav'],
                                daily_growth_rate=nav_item['daily_return'],
                                data_source='akshare'
                            )
                        success_count += 1
                    else:
                        error_count += 1
                    
                    # 发送进度更新
                    progress = int((i + 1) / total_count * 100)
                    send_websocket_notification('fund_nav', {
                        'status': 'running',
                        'message': f'正在下载基金净值 {i+1}/{total_count}',
                        'progress': progress,
                        'total': total_count,
                        'completed': i + 1
                    })
                    
                except Exception as e:
                    logger.error(f"下载基金 {fund.fund_code} 净值失败: {e}")
                    error_count += 1
                    continue
        
        # 更新任务状态
        task.status = 'completed'
        task.completed_at = timezone.now()
        task.save()
        
        # 更新日志
        log.status = 'success'
        log.success_records = success_count
        log.failed_records = error_count
        log.total_records = total_count
        log.end_time = timezone.now()
        log.save()
        
        # 发送完成通知
        send_websocket_notification('fund_nav', {
            'status': 'completed',
            'message': f'基金净值下载完成: 成功 {success_count} 个',
            'progress': 100,
            'total': total_count,
            'completed': success_count
        })
        
        logger.info(f"基金净值下载完成: 成功 {success_count} 个，失败 {error_count} 个")
        return {'success': success_count, 'error': error_count}
        
    except Exception as e:
        error_msg = f"下载基金净值失败: {str(e)}"
        logger.error(error_msg)
        
        try:
            if task is not None:
                task.status = 'failed'
                task.completed_at = timezone.now()
                task.save()
            
            if log is not None:
                log.status = 'failed'
                log.error_message = str(e)
                log.end_time = timezone.now()
                log.save()
        except Exception:
            pass
        
        # 发送错误通知
        send_websocket_notification('fund_nav', {
            'status': 'failed',
            'message': error_msg,
            'progress': 0
        })
        
        return {'success': 0, 'error': 1, 'message': error_msg}

@shared_task
def cleanup_old_sync_logs(days=30):
    """
    清理旧的同步日志
    days: 保留天数
    """
    try:
        from datetime import timedelta
        
        cutoff_date = timezone.now() - timedelta(days=days)
        deleted_count = DataSyncLog.objects.filter(
            created_at__lt=cutoff_date
        ).delete()[0]
        
        logger.info(f"清理了 {deleted_count} 条旧同步日志")
        return {'deleted': deleted_count}
        
    except Exception as e:
        error_msg = f"清理同步日志失败: {str(e)}"
        logger.error(error_msg)
        return {'error': error_msg}